/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

char *strcasestr( const char *phaystack, const char *pneedle )
{
	 const unsigned	char *haystack,	*needle;
	 int	b, c;


	haystack = (const unsigned char*) phaystack;
	needle = (const	unsigned char *) pneedle;

	b = tolower(*needle);
	if( b != '\0' )
	{
		haystack--; /* possible	ANSI violation */
		do
		{
			c = *++haystack;
			if (c == '\0')
				goto ret0;
		}
		while(tolower(c) != (int)b);

		c = tolower(*++needle);
		if (c == '\0')
			goto foundneedle;
		++needle;
		goto jin;

		for(;;)
		{
			int	a;
			const unsigned	char *rhaystack, *rneedle;

			do
			{
				a = *++haystack;
				if(a == '\0')
					goto ret0;
				if( tolower(a) == (int)b )
					break;
				a	=	*++haystack;
				if (a	== '\0')
					goto ret0;
shloop:
				;
			}
			while( tolower(a)!= (int)b );

jin:			a = *++haystack;
			if( a == '\0' )
				goto ret0;

			if( tolower(a) != (int)c )
				goto shloop;

			rhaystack = haystack-- + 1;
			rneedle = needle;
			a = tolower(*rneedle);

			if (tolower(*rhaystack) == (int)a )
				do
				{
					if( a == '\0' )
						goto foundneedle;
					++rhaystack;
					a=tolower(*++needle);
					if( tolower(*rhaystack) != (int)a )
						break;
					if (a== '\0')
						goto foundneedle;
					++rhaystack;
					a = tolower(*++needle);
				}
				while( tolower(*rhaystack) == (int)a );

			needle = rneedle; /* took the register-poor approach */

			if( a == '\0' )
				break;
		}
	}
foundneedle:
	return (char*) haystack;
ret0:
	return 0;
}

#if ( defined _WIN32 )
#define MAX_ARGS 100
#define MAX_ARG_LEN 256

char** CommandLineToArgvA(const char* cmdline, int* argc) {
    if (!cmdline || !argc) return NULL;

    char** args = (char**)malloc(MAX_ARGS * sizeof(char*));
    if (!args) return NULL;

    *argc = 0;
    const char* p = cmdline;

    while (*p && *argc < MAX_ARGS) {
        while (*p == ' ') p++;
        if (!*p) break;

        if (*p == '"') {
            p++;
            char* arg = (char*)malloc(MAX_ARG_LEN);
            if (!arg) {
                FreeArgvA(args, *argc);
                return NULL;
            }
            char* dest = arg;
            while (*p && (dest - arg < MAX_ARG_LEN - 1)) {
                if (*p == '"') {
                    p++;
                    break;
                } else if (*p == '\\' && *(p + 1) == '"') {
                    *dest++ = '"';
                    p += 2;
                } else {
                    *dest++ = *p++;
                }
            }
            *dest = '\0';
            args[(*argc)++] = arg;
        } else {
            char* arg = (char*)malloc(MAX_ARG_LEN);
            if (!arg) {
                FreeArgvA(args, *argc);
                return NULL;
            }
            char* dest = arg;
            while (*p && *p != ' ' && (dest - arg < MAX_ARG_LEN - 1)) {
                *dest++ = *p++;
            }
            *dest = '\0';
            args[(*argc)++] = arg;
        }
    }

    if (*argc < MAX_ARGS) {
        args[*argc] = NULL;
    } else {
        FreeArgvA(args, *argc);
        return NULL;
    }

    return args;
}

void FreeArgvA(char** argv, int argc) {
    if (argv) {
        for (int i = 0; i < argc; i++) {
            free(argv[i]);
        }
        free(argv);
    }
}
#endif

void ReplaceChar( char *str , char src , char dst )
{
	char	*p = NULL ;
	
	for( p = str ; *p ; p++ )
	{
		if( *(p) == src )
			*(p) = dst ;
	}
	
	return;
}

#if ( defined _WIN32 )
char *strndup (const char *s, size_t n)
{
  char *result;
  size_t len = strlen (s);

  if (n < len)
    len = n;

  result = (char *) malloc (len + 1);
  if (!result)
    return 0;

  result[len] = '\0';
  return (char *) memcpy (result, s, len);
}

void *memrchr(const void *str, int c, size_t len)
{
	const unsigned char *cp;

	if (len < 1)
		return NULL;

	cp = (const unsigned char *)str + len;

	do {
		if (*cp == (unsigned char)c)
			return (void *)cp;
	} while (--cp >= (const unsigned char *)str);

	return NULL;
}

unsigned int inet_atoi( const char *c_ipaddr )
{
	unsigned int u_ipaddr = 0;
	unsigned int u_tmp = 0;
	char c;
	int i_base = 10;
	int i_shift = 0;
	int i_recycle = 0;

	c = *c_ipaddr;
	while( 1 )
	{
		u_tmp = 0;
		while( 1 )
		{
			if( isdigit(c) )
			{
				u_tmp = (u_tmp * i_base) + (c - 0x30);
				c = *++c_ipaddr;
			}
			else
			{
				break;
			}
		}

		i_shift = 8*i_recycle++;
		u_tmp <<= i_shift;
		u_ipaddr += u_tmp;

		if( c == '.' )
		{
			c = *++c_ipaddr;
		}
		else
		{
			break;
		}
	}

	if( c != '\0' && ( !isspace(c) ) )
		goto ret_0;

	return u_ipaddr;
ret_0:
	return (0);
}

/*
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
*/
int inet_aton(const char *cp, struct in_addr *ap)
{  
    int dots = 0;  
    register u_long acc = 0, addr = 0;  
  
    do {  
        register char cc = *cp;  
        switch (cc) {  
            case '0': case '1': case '2': case '3':  
            case '4': case '5': case '6': case '7':  
            case '8': case '9':  
                acc = acc * 10 + (cc - '0');  
                break;  
            case '.':  
                if (++dots > 3) {  
                    return 0;  
                }  
                // Fall through  
            case '\0':  
                if (acc > 255) {  
                    return 0;  
                }  
                addr = addr << 8 | acc;  
                acc = 0;  
                break;  
            default:  
                return 0;  
        }  
    } while (*cp++);  
  
    // Normalize the address  
    if (dots < 3) {  
        addr <<= 8 * (3 - dots);  
    }  
  
    // Store it if requested  
    if (ap) {  
        ap->s_addr = htonl(addr);  
    }  
    return 1;  
}

/*
#include <sys/types.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>  
#include <string.h>  
#include <errno.h>  
*/
/*
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
{  
    static const char *inet_ntop_err = "Invalid argument";  
    const char *p;  
    char tmp[INET6_ADDRSTRLEN];  
    int i, len;  
  
    // Check the address family  
    switch (af) {  
        case AF_INET:  
            // IPv4  
            p = (const char *)src;  
            len = snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u",  
                           (unsigned char)p[0],  
                           (unsigned char)p[1],  
                           (unsigned char)p[2],  
                           (unsigned char)p[3]);  
            break;  
  
        // Add IPv6 case here if needed (omitted for brevity)  
  
        default:  
            errno = EAFNOSUPPORT;  
            return NULL;  
    }  
  
    // Check the buffer size  
    if (len >= cnt) {  
        errno = ENOSPC;  
        return NULL;  
    }  
  
    // Copy the result to the destination buffer  
    memcpy(dst, tmp, len);  
    dst[len] = '\0';  
  
    return dst;  
}
*/

#define ALT_E          0x01
#define ALT_O          0x02
 //#define LEGAL_ALT(x)       { if (alt_format & ~(x)) return (0); }
#define LEGAL_ALT(x)       { ; }
#define TM_YEAR_BASE   (1900)
static int _conv_num(const char **buf, int *dest, int llim, int ulim)
{
        int result = 0;

        /* The limit also determines the number of valid digits. */
        int rulim = ulim;

        if (**buf < '0' || **buf > '9')
                return (0);

        do {
                result *= 10;
                result += *(*buf)++ - '0';
                rulim /= 10;
        } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');

        if (result < llim || result > ulim)
                return (0);

        *dest = result;
        return (1);
}
static int _strncasecmp(char *s1, char *s2, size_t n)
{
        if (n == 0)
                return 0;

        while (n-- != 0 && tolower(*s1) == tolower(*s2))
        {
                if (n == 0 || *s1 == '\0' || *s2 == '\0')
                        break;
                s1++;
                s2++;
        }

        return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
}
static const char *day[7] = {
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
        "Friday", "Saturday"
};
static const char *abday[7] = {
        "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
static const char *mon[12] = {
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
};
static const char *abmon[12] = {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const char *am_pm[2] = {
        "AM", "PM"
};
char *strptime(const char *buf, const char *fmt, struct tm *tm)
{
        char c;
        const char *bp;
        size_t len = 0;
        int alt_format, i, split_year = 0;

        bp = buf;

        while ((c = *fmt) != '\0') {
                /* Clear `alternate' modifier prior to new conversion. */
                alt_format = 0;

                /* Eat up white-space. */
                if (isspace(c)) {
                        while (isspace(*bp))
                                bp++;

                        fmt++;
                        continue;
                }

                if ((c = *fmt++) != '%')
                        goto literal;


        again:        switch (c = *fmt++) {
        case '%': /* "%%" is converted to "%". */
                literal:
                        if (c != *bp++)
                                return (0);
                break;

                /*
                * "Alternative" modifiers. Just set the appropriate flag
                * and start over again.
                */
        case 'E': /* "%E?" alternative conversion modifier. */
                LEGAL_ALT(0);
                alt_format |= ALT_E;
                goto again;

        case 'O': /* "%O?" alternative conversion modifier. */
                LEGAL_ALT(0);
                alt_format |= ALT_O;
                goto again;

                /*
                * "Complex" conversion rules, implemented through recursion.
                */
        case 'c': /* Date and time, using the locale's format. */
                LEGAL_ALT(ALT_E);
                if (!(bp = strptime(bp, "%x %X", tm)))
                        return (0);
                break;

        case 'D': /* The date as "%m/%d/%y". */
                LEGAL_ALT(0);
                if (!(bp = strptime(bp, "%m/%d/%y", tm)))
                        return (0);
                break;

        case 'R': /* The time as "%H:%M". */
                LEGAL_ALT(0);
                if (!(bp = strptime(bp, "%H:%M", tm)))
                        return (0);
                break;

        case 'r': /* The time in 12-hour clock representation. */
                LEGAL_ALT(0);
                if (!(bp = strptime(bp, "%I:%M:%S %p", tm)))
                        return (0);
                break;

        case 'T': /* The time as "%H:%M:%S". */
                LEGAL_ALT(0);
                if (!(bp = strptime(bp, "%H:%M:%S", tm)))
                        return (0);
                break;

        case 'X': /* The time, using the locale's format. */
                LEGAL_ALT(ALT_E);
                if (!(bp = strptime(bp, "%H:%M:%S", tm)))
                        return (0);
                break;

        case 'x': /* The date, using the locale's format. */
                LEGAL_ALT(ALT_E);
                if (!(bp = strptime(bp, "%m/%d/%y", tm)))
                        return (0);
                break;

                /*
                * "Elementary" conversion rules.
                */
        case 'A': /* The day of week, using the locale's form. */
        case 'a':
                LEGAL_ALT(0);
                for (i = 0; i < 7; i++) {
                        /* Full name. */
                        len = strlen(day[i]);
                        if (_strncasecmp((char *)(day[i]), (char *)bp, len) == 0)
                                break;

                        /* Abbreviated name. */
                        len = strlen(abday[i]);
                        if (_strncasecmp((char *)(abday[i]), (char *)bp, len) == 0)
                                break;
                }

                /* Nothing matched. */
                if (i == 7)
                        return (0);

                tm->tm_wday = i;
                bp += len;
                break;

        case 'B': /* The month, using the locale's form. */
        case 'b':
        case 'h':
                LEGAL_ALT(0);
                for (i = 0; i < 12; i++) {
                        /* Full name. */
                        len = strlen(mon[i]);
                        if (_strncasecmp((char *)(mon[i]), (char *)bp, len) == 0)
                                break;

                        /* Abbreviated name. */
                        len = strlen(abmon[i]);
                        if (_strncasecmp((char *)(abmon[i]),(char *) bp, len) == 0)
                                break;
                }

                /* Nothing matched. */
                if (i == 12)
                        return (0);

                tm->tm_mon = i;
                bp += len;
                break;

        case 'C': /* The century number. */
                LEGAL_ALT(ALT_E);
                if (!(_conv_num(&bp, &i, 0, 99)))
                        return (0);

                if (split_year) {
                        tm->tm_year = (tm->tm_year % 100) + (i * 100);
                } else {
                        tm->tm_year = i * 100;
                        split_year = 1;
                }
                break;

        case 'd': /* The day of month. */
        case 'e':
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
                        return (0);
                break;

        case 'k': /* The hour (24-hour clock representation). */
                LEGAL_ALT(0);
                /* FALLTHROUGH */
        case 'H':
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
                        return (0);
                break;

        case 'l': /* The hour (12-hour clock representation). */
                LEGAL_ALT(0);
                /* FALLTHROUGH */
        case 'I':
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
                        return (0);
                if (tm->tm_hour == 12)
                        tm->tm_hour = 0;
                break;

        case 'j': /* The day of year. */
                LEGAL_ALT(0);
                if (!(_conv_num(&bp, &i, 1, 366)))
                        return (0);
                tm->tm_yday = i - 1;
                break;

        case 'M': /* The minute. */
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
                        return (0);
                break;

        case 'm': /* The month. */
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &i, 1, 12)))
                        return (0);
                tm->tm_mon = i - 1;
                break;

                //       case 'p': /* The locale's equivalent of AM/PM. */
                //            LEGAL_ALT(0);
                //            /* AM? */
                //            if (strcasecmp(am_pm[0], bp) == 0) {
                //                 if (tm->tm_hour > 11)
                //                     return (0);
                //
                //                 bp += strlen(am_pm[0]);
                //                 break;
                //            }
                //            /* PM? */
                //            else if (strcasecmp(am_pm[1], bp) == 0) {
                //                 if (tm->tm_hour > 11)
                //                     return (0);
                //
                //                 tm->tm_hour += 12;
                //                 bp += strlen(am_pm[1]);
                //                 break;
                //            }
                //
                //            /* Nothing matched. */
                //            return (0);

        case 'S': /* The seconds. */
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
                        return (0);
                break;

        case 'U': /* The week of year, beginning on sunday. */
        case 'W': /* The week of year, beginning on monday. */
                LEGAL_ALT(ALT_O);
                /*
                * XXX This is bogus, as we can not assume any valid
                * information present in the tm structure at this
                * point to calculate a real value, so just check the
                * range for now.
                */
                if (!(_conv_num(&bp, &i, 0, 53)))
                        return (0);
                break;

        case 'w': /* The day of week, beginning on sunday. */
                LEGAL_ALT(ALT_O);
                if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
                        return (0);
                break;

        case 'Y': /* The year. */
                LEGAL_ALT(ALT_E);
                if (!(_conv_num(&bp, &i, 0, 9999)))
                        return (0);

                tm->tm_year = i - TM_YEAR_BASE;
                break;

        case 'y': /* The year within 100 years of the epoch. */
                LEGAL_ALT(ALT_E | ALT_O);
                if (!(_conv_num(&bp, &i, 0, 99)))
                        return (0);

                if (split_year) {
                        tm->tm_year = ((tm->tm_year / 100) * 100) + i;
                        break;
                }
                split_year = 1;
                if (i <= 68)
                        tm->tm_year = i + 2000 - TM_YEAR_BASE;
                else
                        tm->tm_year = i + 1900 - TM_YEAR_BASE;
                break;

                /*
                * Miscellaneous conversions.
                */
        case 'n': /* Any kind of white-space. */
        case 't':
                LEGAL_ALT(0);
                while (isspace(*bp))
                        bp++;
                break;


        default: /* Unknown/unsupported conversion. */
                return (0);
        }


        }

        /* LINTED functional specification */
        return ((char *)bp);
}

int gettimeofday( struct timeval *tv , struct timezone *tz )
{
	SYSTEMTIME	st ;

	tv->tv_sec = (long)time(NULL) ;
	GetLocalTime( & st );
	tv->tv_usec = st.wMilliseconds*1000 ;

	return 0;
}
#endif

char *StrdupEntireFile( char *pathfilename , int *p_file_size )
{
	struct stat	st ;
	char		*file_content = NULL ;
	int		file_size ;
	FILE		*fp = NULL ;
	
	int		nret = 0 ;
	
	nret = stat( pathfilename , & st ) ;
	if( nret == -1 )
	{
		return NULL;
	}
	file_size = (int)(st.st_size) ;
	
	file_content = (char*)malloc( file_size+1 ) ;
	if( file_content == NULL )
	{
		return NULL;
	}
	memset( file_content , 0x00 , file_size+1 );
	
	fp = fopen( pathfilename , "rb" ) ;
	if( fp == NULL )
	{
		return NULL;
	}
	
	nret = (int)fread( file_content , (size_t)file_size , 1 , fp ) ;
	if( nret != 1 )
	{
		return NULL;
	}
	
	fclose( fp );
	
	if( p_file_size )
		(*p_file_size) = file_size ;
	return file_content;
}

int GetIpByDomainName( char *domain_name , size_t *ip_count , struct Ipv4DnsResolution **ip_array )
{
	ADDRINFO			hint ;
	ADDRINFO			*res = NULL ;
	ADDRINFO			*curr = NULL ;
	size_t				count ;
	struct Ipv4DnsResolution	*array = NULL , *p = NULL ;
	int				nret = 0 ;
	
	memset( & hint , 0x00 , sizeof(ADDRINFO) );
	hint.ai_family = AF_INET ;
	hint.ai_socktype = SOCK_STREAM ;
	nret = getaddrinfo( domain_name , NULL , & hint , & res ) ;
	if( nret )
		return nret;
	
	for( curr = res , count = 0 ; curr ; curr = curr->ai_next , count++ );
	array = (struct Ipv4DnsResolution *)malloc( sizeof(struct Ipv4DnsResolution) * count ) ;
	if( array == NULL )
		return -1;
	
	for( curr = res , p = array ; curr ; curr = curr->ai_next , p++ )
	{
		p->ip_num = ((struct sockaddr_in *)(curr->ai_addr))->sin_addr.s_addr ;
		inet_ntop( AF_INET , (void*) & (p->ip_num) , p->ip_str , sizeof(p->ip_str) );
	}
	
	freeaddrinfo( res );
	
	if( ip_count )
		(*ip_count) = count ;
	if( ip_array )
		(*ip_array) = array ;
	else
		free( array );
	return 0;
}

int IsMatchString(char *match_str, char *object_str, char match_much_characters, char match_one_character)
{
	if( match_str == NULL || object_str == NULL || match_much_characters == '\0' || match_one_character == '\0' )
		return -3;
	
	int el=(int)strlen(match_str);
	int sl=(int)strlen(object_str);
	char cs,ce;

	int is,ie;
	int last_xing_pos=-1;

	for(is=0,ie=0;is<sl && ie<el;){
		cs=object_str[is];
		ce=match_str[ie];

		if(cs!=ce){
			if(ce==match_much_characters){
				last_xing_pos=ie;
				ie++;
			}else if(ce==match_one_character){
				is++;
				/*
				if((unsigned)(cs)>0x7f && is+1>=sl)
					is++;
				*/
				ie++;
			}else if(last_xing_pos>=0){
				while(ie>last_xing_pos){
					ce=match_str[ie];
					if(ce==cs)
						break;
					ie--;
				}

				if(ie==last_xing_pos)
					is++;
			}else
				return -1;
		}else{
			is++;
			ie++;
		}
	}

	if(object_str[is]==0 && match_str[ie]==0)
		return 0;

	if(match_str[ie]==0)
		ie--;

	if(ie>=0){
		while(match_str[ie])
			if(match_str[ie++]!=match_much_characters)
				return -2;
	} 

	return 0;
}

int EscapeString( char *str )
{
	char	*p1 = NULL , *p2 = NULL ;
	int	len ;
	
	p1 = p2 = str ;
	len = 0 ;
	while( (*p2) )
	{
		if( (*p2) == '\\' )
		{
			p2++;
			if( (*p2) == 'a' )
			{
				(*p1) = '\a' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 'b' )
			{
				(*p1) = '\b' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 't' )
			{
				(*p1) = '\t' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 'n' )
			{
				(*p1) = '\n' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 'v' )
			{
				(*p1) = '\v' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 'f' )
			{
				(*p1) = '\f' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == 'r' )
			{
				(*p1) = '\r' ;
				p1++; len++;
				p2++;
			}
			else if( (*p2) == '\0' )
			{
				(*p1) = '\\' ;
				p1++; len++;
				return len;
			}
			else
			{
				(*p1) = (*p2) ;
				p1++; len++;
				p2++;
			}
		}
		else
		{
			(*p1) = (*p2) ;
			p1++; len++;
			p2++;
		}
	}
	
	(*p1) = '\0' ;
	return len;
}

int32_t TrimNumericLiteralUnderlineUnsafely( char *token , int32_t token_len , char *numeric_buffer )
{
	int32_t		numeric_buffer_len ;
	int32_t		i ;
	
	numeric_buffer_len = 0 ;
	for( i = 0 ; i < token_len ; i++ , token++ )
	{
		if( (*token) != '_' )
		{
			(*numeric_buffer++) = (*token) ;
			numeric_buffer_len++;
		}
	}
	(*numeric_buffer) = '\0' ;
	
	return numeric_buffer_len;
}

char *GetFilenamePtr( char *pathfilename )
{
	char	*p = NULL ;

	p = strrchr( pathfilename , DIRECTORY_SEPARATOR_CHAR ) ;
	if( p == NULL )
		return NULL;
	else
		return p+1;
}

int GetDirectoryOrFileType( char *pathfilename )
{
#if ( defined __linux__ ) || ( defined __unix ) || ( defined _AIX )
	struct stat	stat_buf;
	int		nret;
	
	nret = lstat( pathfilename , & stat_buf );
	if( nret == -1 )
		return -1;
	
	if( S_ISDIR(stat_buf.st_mode) )
		return FILE_TYPE_DIRECTORY;
	else if( S_ISREG(stat_buf.st_mode) )
		return FILE_TYPE_REGULAR;
	else if( S_ISCHR(stat_buf.st_mode) )
		return FILE_TYPE_CHARACTER;
	else if( S_ISBLK(stat_buf.st_mode) )
		return FILE_TYPE_BLOCK;
	else if( S_ISFIFO(stat_buf.st_mode) )
		return FILE_TYPE_FIFO;
	else if( S_ISSOCK(stat_buf.st_mode) )
		return FILE_TYPE_SOCKET;
	else if( S_ISLNK(stat_buf.st_mode) )
		return FILE_TYPE_LINK;
	else
		return FILE_TYPE_OTHER;
#elif defined(_WIN32)
	struct _stat	_stat_buf;
	int		nret;
	
	nret = _stat( pathfilename , & _stat_buf) ;
	if( nret == -1 )
		return -1;
	
	if( _S_IFDIR & _stat_buf.st_mode )
		return FILE_TYPE_DIRECTORY;
	else if( _S_IFREG & _stat_buf.st_mode )
		return FILE_TYPE_REGULAR;
	else if( _S_IFCHR & _stat_buf.st_mode )
		return FILE_TYPE_CHARACTER;
	else if( _S_IFIFO & _stat_buf.st_mode )
		return FILE_TYPE_FIFO;
	else
		return FILE_TYPE_OTHER;
#else
	return -2;
#endif
}

void GetDirectoryWithFileOrCurrentDirectory( char *filename , char *pathname , size_t pathname_size )
{
	char	*p = NULL ;
	
	p = strrchr( filename , '/' ) ;
	if( p == NULL )
	{
		p = strrchr( filename , '\\' ) ;
		if( p == NULL )
		{
#if defined(__linux__)
			getcwd( pathname , pathname_size );
#elif defined(_WIN32)
			GetCurrentDirectory( (DWORD)pathname_size , pathname );
#endif
			return;
		}
	}
	
	snprintf( pathname , pathname_size , "%.*s" , (int)(p-filename),filename );
	return;
}

#if defined(_WIN32)
unsigned int sleep( unsigned int sec )
{
	Sleep( sec*1000);

	return 0;
}

int usleep( useconds_t usec )
{
	HANDLE	timer ;
	LARGE_INTEGER	interval ;
	interval.QuadPart = 10*usec ;
	interval.QuadPart = -interval.QuadPart ;

	timer = CreateWaitableTimer( NULL , TRUE , NULL ) ;
	SetWaitableTimer( timer , & interval , 0 , NULL , NULL , 0 );
	WaitForSingleObject( timer , INFINITE );
	CloseHandle( timer );

	return 0;
}

int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
	HANDLE	timer ;
	LARGE_INTEGER	interval ;
	interval.QuadPart = rqtp->tv_sec*10000000 + rqtp->tv_nsec/100 ;
	interval.QuadPart = -interval.QuadPart ;

	timer = CreateWaitableTimer( NULL , TRUE , NULL ) ;
	SetWaitableTimer( timer , & interval , 0 , NULL , NULL , 0 );
	WaitForSingleObject( timer , INFINITE );
	CloseHandle( timer );

	return 0;
}
#endif

#if defined(_WIN32)
char *_stristr(const char* str, const char* substr) {
    char* str_lower = STRDUP(str);
    char* substr_lower = STRDUP(substr);
    char* ptr;
 
    // Convert str and substr to lowercase.
    for (ptr = str_lower; *ptr != '\0'; ptr++) {
        *ptr = tolower((unsigned char)*ptr);
    }
    for (ptr = substr_lower; *ptr != '\0'; ptr++) {
        *ptr = tolower((unsigned char)*ptr);
    }
 
    // Find the first occurrence of substr in str using strstr.
    char* found = strstr(str_lower, substr_lower);
 
    // Free the lowercase strings and return the original occurrence.
    free(str_lower);
    free(substr_lower);
    return found ? (char*)str + (found - str_lower) : NULL;
}
#endif

#if defined(_WIN32)
int setenv(const char *name,const char * value,int overwrite)
{
	char	*name_and_val_buf = NULL ;
	int	nret ;
	/*
	BOOL	b ;
	*/

	name_and_val_buf = malloc( strlen(name) + 1 + strlen(value) + 1 ) ;
	if( name_and_val_buf == NULL )
		return -1;
	sprintf( name_and_val_buf , "%s=%s" , name , value );

	nret = _putenv( name_and_val_buf ) ;
	free( name_and_val_buf );
	if( nret )
		return -2;

	/*
	b = SetEnvironmentVariable( name , value ) ;
	if( b != TRUE )
		return -11;
	else
		return 0;
	*/
	return 0;
}
#endif

TLS struct StackFrameInfo	_stack_frames_info[ STACKFRAME_MAX_STACK_FRAMES_INFO ] = { { "" } } ;

#if defined(__linux__)
#include <execinfo.h>


struct StackFrameInfo *GetStackFramesInfo( CONTEXT *p_thread_context , size_t *p_stack_frame_count )
{
	char		exe_filename[ 1024 ] = "" ;
	int		exe_filename_len ;
	
	void		*_backtrace_addresses[ STACKFRAME_MAX_STACK_FRAMES_INFO ] = { NULL } ;
	char		**_backtrace_symbols_string = NULL ;
	int		stack_frame_no , stack_frame_count ;

	char		*endover_so_filename = NULL ;
	char		*begin_offset = NULL ;
	char		*endover_offset = NULL ;

	char		proc_maps_cmd[ 1024 ] = "" ;
	char		proc_maps_output[ 1024 ] = "" ;
	char		addr2line_cmd[ 1024 ] = "" ;
	char		addr2line_output[ 1024 ] = "" ;
	FILE		*in = NULL ;
	char		*p = NULL ;
	uint64_t	offset_addr ;
	
	char		*endover_func_name = NULL ;
	char		*begin_source_filename = NULL ;
	char		*endover_source_filename = NULL ;
	char		*begin_lineno = NULL ;
	
	exe_filename_len = readlink( "/proc/self/exe" , exe_filename , sizeof(exe_filename) ) ;
	if( exe_filename_len == -1 )
		return NULL;
	
	stack_frame_count = backtrace( _backtrace_addresses , STACKFRAME_MAX_STACK_FRAMES_INFO ) ;
	_backtrace_symbols_string = backtrace_symbols( _backtrace_addresses , stack_frame_count ) ;
	
	memset( _stack_frames_info , 0x00 , sizeof(_stack_frames_info) );
	for( stack_frame_no = 0 ; stack_frame_no < stack_frame_count ; stack_frame_no++ )
	{
		endover_so_filename = strchr( _backtrace_symbols_string[stack_frame_no] , '(' );
		if( endover_so_filename == NULL )
		{
			free( _backtrace_symbols_string );
			return NULL;
		}
		begin_offset = strchr( _backtrace_symbols_string[stack_frame_no] , '[' );
		if( begin_offset == NULL )
		{
			free( _backtrace_symbols_string );
			return NULL;
		}
		begin_offset += 3 ;
		endover_offset = strchr( begin_offset , ']' ); 
		if( endover_offset == NULL )
		{
			free( _backtrace_symbols_string );
			return NULL;
		}
		
		memset( proc_maps_cmd , 0x00 , sizeof(proc_maps_cmd) );
		snprintf( proc_maps_cmd , sizeof(proc_maps_cmd) , "grep \"%.*s\" /proc/%d/maps | awk -F- '{if($1<=\"%.*s\"&&\"%.*s\"<$2)print $1}'" , (int)(endover_so_filename-_backtrace_symbols_string[stack_frame_no]),_backtrace_symbols_string[stack_frame_no] , getpid() , (int)(endover_offset-begin_offset),begin_offset , (int)(endover_offset-begin_offset),begin_offset );
		in = popen( proc_maps_cmd , "r" );
		if( in == NULL )
		{
			free( _backtrace_symbols_string );
			return NULL;
		}
		memset( proc_maps_output , 0x00 , sizeof(proc_maps_output) );
		if( fgets( proc_maps_output , sizeof(proc_maps_output) , in ) == NULL )
		{
			snprintf( _stack_frames_info[stack_frame_no].func_name , sizeof(_stack_frames_info[stack_frame_no].func_name) , "(0x%p:%s)" , _backtrace_addresses[stack_frame_no] , _backtrace_symbols_string[stack_frame_no] );
			_stack_frames_info[stack_frame_no].source_filename[0] = '\0' ;
			_stack_frames_info[stack_frame_no].source_fileline = 0 ;
			_stack_frames_info[stack_frame_no].stack_top = (long)(_backtrace_addresses[stack_frame_no]) ;
		}
		else
		{
			{
				char		*endptr = NULL ;
				uint64_t	addr ;
				uint64_t	base_addr ;
				addr = strtol( begin_offset , & endptr , 16 ) ;
				base_addr = strtol( proc_maps_output , & endptr , 16 ) ;
				offset_addr = addr - base_addr ;
			}
			
			memset( addr2line_cmd , 0x00 , sizeof(addr2line_cmd) );
			snprintf( addr2line_cmd , sizeof(addr2line_cmd)-1 , "addr2line 0x%lx -e %.*s -f -p" , offset_addr , (int)(endover_so_filename-_backtrace_symbols_string[stack_frame_no]),_backtrace_symbols_string[stack_frame_no] );
			in = popen( addr2line_cmd , "r" );
			if( in == NULL )
			{
				free( _backtrace_symbols_string );
				return NULL;
			}
			memset( addr2line_output , 0x00 , sizeof(addr2line_output) );
			if( fgets( addr2line_output , sizeof(addr2line_output) , in ) == NULL )
			{
				free( _backtrace_symbols_string );
				return NULL;
			}
			p = strchr( addr2line_output , ':' ) ;
			if( p == NULL )
			{
				free( _backtrace_symbols_string );
				return NULL;
			}
			
			endover_func_name = strstr( addr2line_output , " at " ) ;
			snprintf( _stack_frames_info[stack_frame_no].func_name , STACKFRAME_MAX_FUNCTION_NAME , "%.*s" , (int)(endover_func_name-addr2line_output),addr2line_output );
			begin_source_filename = endover_func_name + sizeof(" at ")-1 ;
			endover_source_filename = strchr( begin_source_filename , ':' ) ;
			snprintf( _stack_frames_info[stack_frame_no].source_filename , STACKFRAME_MAX_SOURCE_FILENAME , "%.*s" , (int)(endover_source_filename-begin_source_filename),begin_source_filename );
			begin_lineno = endover_source_filename+1 ;
			_stack_frames_info[stack_frame_no].source_fileline = atoi(begin_lineno) ;
			_stack_frames_info[stack_frame_no].stack_top = 0 ;
		}
	}
	
	for( stack_frame_no = 0 ; stack_frame_no < stack_frame_count-1 ; stack_frame_no++ )
	{
		_stack_frames_info[stack_frame_no].stack_depth = _stack_frames_info[stack_frame_no+1].stack_top - _stack_frames_info[stack_frame_no].stack_top ;
	}
	
	free( _backtrace_symbols_string );
	
	if( p_stack_frame_count )
		(*p_stack_frame_count) = stack_frame_count ;
	return _stack_frames_info;
}
#elif defined(_WIN32)
#include <processthreadsapi.h>
#include <DbgHelp.h>

struct StackFrameInfo *GetStackFramesInfo( CONTEXT *p_thread_context , size_t *p_stack_frame_count )
{
	HANDLE			process_handle ;
	HANDLE			thread_handle ;
	DWORD			machine_type ;
	STACKFRAME64		stack_frame = { 0 } ;
	DWORD64			displament = 0 ;
	char			image_symbol_buffer[ sizeof(IMAGEHLP_SYMBOL64) + STACKFRAME_MAX_FUNCTION_NAME + 1 ] = "" ;
	IMAGEHLP_SYMBOL64	*p_image_symbol = (IMAGEHLP_SYMBOL64*) image_symbol_buffer ;
	IMAGEHLP_LINE64		image_line = { 0 } ;
	size_t			stack_frame_no , stack_frame_count ;
	
	process_handle = GetCurrentProcess() ;
	SymInitialize( process_handle , NULL , TRUE );
	thread_handle = GetCurrentThread() ;
	p_image_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64) ;
	p_image_symbol->MaxNameLength = STACKFRAME_MAX_FUNCTION_NAME ;
	image_line.SizeOfStruct = sizeof(IMAGEHLP_LINE64) ;

	stack_frame.AddrPC.Mode = AddrModeFlat;
	stack_frame.AddrFrame.Mode = AddrModeFlat;
	stack_frame.AddrStack.Mode = AddrModeFlat;
#ifdef _M_IX86
	stack_frame.AddrPC.Offset = p_thread_context->Eip;
	stack_frame.AddrFrame.Offset = p_thread_context->Ebp;
	stack_frame.AddrStack.Offset = p_thread_context->Esp;
	machine_type = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
	stack_frame.AddrPC.Offset = p_thread_context->Rip;
	stack_frame.AddrFrame.Offset = p_thread_context->Rbp;
	stack_frame.AddrStack.Offset = p_thread_context->Rsp;
	machine_type = IMAGE_FILE_MACHINE_AMD64;
#elif _M_IA64
	stack_frame.AddrPC.Offset = p_thread_context->StIIP;
	stack_frame.AddrFrame.Offset = p_thread_context->IntSp;
	stack_frame.AddrStack.Offset = p_thread_context->IntSp;
	machine_type = IMAGE_FILE_MACHINE_IA64;
	stack_frame.AddrBStore.Offset = p_thread_context->RsBSP;
	stack_frame.AddrBStore.Mode = AddrModeFlat;
#else
	stack_frame.AddrPC.Offset = p_thread_context->Eip;
	stack_frame.AddrFrame.Offset = p_thread_context->Ebp;
	stack_frame.AddrStack.Offset = p_thread_context->Esp;
	machine_type = IMAGE_FILE_MACHINE_I386;
#endif

	stack_frame_no = 0 ;
	while( StackWalk64( machine_type , process_handle , thread_handle , & stack_frame , p_thread_context , NULL , SymFunctionTableAccess64 , SymGetModuleBase64 , NULL ) )
	{
		if( stack_frame_no >= STACKFRAME_MAX_STACK_FRAMES_INFO )
			break;
		
		SymGetSymFromAddr64( process_handle, stack_frame.AddrPC.Offset , & displament , p_image_symbol );
		SymGetLineFromAddr64( process_handle , stack_frame.AddrPC.Offset , & (DWORD)displament , & image_line );

		if( p_image_symbol->Name[0] )
		{
			strncpy( _stack_frames_info[stack_frame_no].func_name , p_image_symbol->Name , STACKFRAME_MAX_FUNCTION_NAME );
		}
		if( image_line.FileName )
		{
			strncpy( _stack_frames_info[stack_frame_no].source_filename , image_line.FileName , STACKFRAME_MAX_SOURCE_FILENAME );
			_stack_frames_info[stack_frame_no].source_fileline = image_line.LineNumber ;
		}
		_stack_frames_info[stack_frame_no].stack_top = (signed long)(stack_frame.AddrStack.Offset) ;

		stack_frame_no++;
	}
	stack_frame_count = stack_frame_no ;

	for( stack_frame_no = 0 ; stack_frame_no < stack_frame_count-1 ; stack_frame_no++ )
	{
		_stack_frames_info[stack_frame_no].stack_depth = _stack_frames_info[stack_frame_no+1].stack_top - _stack_frames_info[stack_frame_no].stack_top ;
	}

#if 0
	memcpy( & stack_frame_travel , & stack_frame_init , sizeof(STACKFRAME64) );
	memcpy( & thread_context_travel , & thread_context_init , sizeof(CONTEXT) );
	stack_frame_no = 0 ;
	alloc_size = 0 ;
	while( StackWalk64( machine_type , process_handle , thread_handle , & stack_frame_travel , & thread_context_travel , NULL , SymFunctionTableAccess64 , SymGetModuleBase64 , NULL ) )
	{
		stack_frame_no++;
		
		SymGetSymFromAddr64( process_handle , stack_frame_travel.AddrPC.Offset , & displament , p_image_symbol );
		SymGetLineFromAddr64( process_handle , stack_frame_travel.AddrPC.Offset , & displament , & image_line );

		if( p_image_symbol->Name[0] )
			alloc_size += strlen(p_image_symbol->Name) + 1 ;
		if( image_line.FileName )
			alloc_size += strlen(image_line.FileName) + 1 ;
	}
	if( stack_frame_no == 0 || alloc_size == 0 )
		return NULL;
	stack_frame_count = stack_frame_no ;
	alloc_size++;

	stack_frame_info = (struct StackFrameInfo *)malloc( sizeof(struct StackFrameInfo) * stack_frame_count ) ;
	if( stack_frame_info == NULL )
		return NULL;
	memset( stack_frame_info , 0x00 , sizeof(struct StackFrameInfo) * stack_frame_count );

	stack_frame_info_buf = (char*)malloc( alloc_size ) ;
	if( stack_frame_info_buf == NULL )
	{
		free( stack_frame_info );
		return NULL;
	}
	memset( stack_frame_info_buf , 0x00 , alloc_size );
	stack_frame_info_ptr = stack_frame_info_buf ;

	memcpy( & stack_frame_travel , & stack_frame_init , sizeof(STACKFRAME64) );
	memcpy( & thread_context_travel , & thread_context_init , sizeof(CONTEXT) );
	stack_frame_no = 0 ;
	while( StackWalk64( machine_type , process_handle , thread_handle , & stack_frame_travel , & thread_context_travel , NULL , SymFunctionTableAccess64 , SymGetModuleBase64 , NULL ) )
	{
		SymGetSymFromAddr64( process_handle , stack_frame_travel.AddrPC.Offset , & displament , p_image_symbol );
		SymGetLineFromAddr64( process_handle , stack_frame_travel.AddrPC.Offset , & displament , & image_line );

		if( p_image_symbol->Name[0] )
		{
			len = sprintf( stack_frame_info_ptr , "%s" , p_image_symbol->Name ) ;
			stack_frame_info[stack_frame_no].func_name = stack_frame_info_ptr ; stack_frame_info_ptr += len + 1 ;
		}
		if( image_line.FileName )
		{
			len = sprintf( stack_frame_info_ptr , "%s" , image_line.FileName ) ;
			stack_frame_info[stack_frame_no].source_filename = stack_frame_info_ptr ; stack_frame_info_ptr += len + 1 ;
			stack_frame_info[stack_frame_no].source_fileline = image_line.LineNumber ;
		}
		stack_frame_info[stack_frame_no].stack_top = stack_frame_travel.AddrStack.Offset ;

		stack_frame_no++;
	}

	for( stack_frame_no = 0 ; stack_frame_no < stack_frame_count-1 ; stack_frame_no++ )
	{
		stack_frame_info[stack_frame_no].stack_depth = stack_frame_info[stack_frame_no+1].stack_top - stack_frame_info[stack_frame_no].stack_top ;
	}
#endif

	SymCleanup( process_handle );
	
	if( p_stack_frame_count )
		(*p_stack_frame_count) = stack_frame_count ;
	return _stack_frames_info;
}
#endif
